package com.huawang.mdesign.model.service.inter;

import com.huawang.business.command.CommandAddType;
import com.huawang.business.command.CommandParameter;
import com.huawang.business.constants.ErrorCode;
import com.huawang.business.constants.ModelConstantURI;
import com.huawang.business.dto.project.Project;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.model.base.UmlService;
import com.huawang.business.service.model.core.InternalUmlService;
import com.huawang.business.service.model.core.project.ProjectManager;
import com.huawang.business.service.transaction.TransactionServiceImpl;
import com.huawang.business.util.InstanceVoUtils;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRObject;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.semantics.entity.MofPropertyInfo;
import com.huawang.core.semantics.entity.transaction.LocalTransaction;
import com.huawang.core.semantics.exception.LocalTransactionNotStartException;
import com.huawang.core.semantics.exception.TransactionNotExistingException;
import com.huawang.core.semantics.utils.TransformUtil;
import com.huawang.mdesign.model.service.constant.UAFDefinitionConstants;
import com.huawang.mdesign.model.service.request.uaf.CreateExchangeDto;
import com.huawang.mdesign.model.service.request.uaf.ExchangeDto;
import com.huawang.mdesign.model.service.request.uaf.UpdateExchangeDto;
import com.huawang.mdesign.model.service.util.uaf.ExchangeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.huawang.business.constants.ModelActionName.ADD_MODEL;
import static com.huawang.business.constants.ModelActionName.UPDATE_PROPERTY;

@Service
@Primary
@Slf4j
public class UAFExchangeService {
    @Autowired
    private ProjectManager projectManager;

    @Autowired
    private UmlService umlService;

    @Autowired
    private InternalUmlService internalUmlService;

    @Autowired
    private TransactionServiceImpl transactionService;

    /**
     * 创建交换
     *
     * @param createExchangeDto
     * @return
     */
    @NotNull
    public ModelResultVo createExchange(CreateExchangeDto createExchangeDto) {
        ModelResultVo modelResultVo = new ModelResultVo();
        final String projectId = createExchangeDto.getProjectId();
        final Project project = projectManager.getProject(projectId);
        if (Objects.isNull(project)) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_NOT_FOUND);
        }
        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        // 创建Exchange
        CommandParameter parameter = CommandParameter.builder()
                .type(CommandAddType.RELATIONSHIP)
                .typeId(UMLDefinitionConstants.InformationFlow)
                .projectId(createExchangeDto.getProjectId())
                .instanceId(ModelConstantURI.initInstanceId())
                .source(createExchangeDto.getSource())
                .target(createExchangeDto.getTarget())
                .parentId(null)
                .applyStereotypes(createExchangeDto.getApplyStereotypes())
                .build();
        try {
            MetaClassInstance result = umlService.addModel(parameter);
            modelResultVo.setInstanceId(result.getId());
            updateExchangeRelated(projectId, createExchangeDto, result, transaction, modelResultVo);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }
        return modelResultVo;
    }

    /**
     * 更新转换相关的属性
     *
     * @param exchangeDto
     * @param instance
     * @return
     */
    @NotNull
    public Set<String> updateExchangeProperties(ExchangeDto exchangeDto, MetaClassInstance instance) {
        Set<String> affectedRelations = new HashSet<>();
        List<String> conveyedItems = exchangeDto.getConveyedItems();
        List<MetaClassInstance> conveyedItemInstances = internalUmlService.fetchInstanceByIds(conveyedItems, exchangeDto.getProjectId());
        umlService.updateModel(exchangeDto.getProjectId(), instance.getId(),
                UMLDefinitionConstants.InformationFlow_conveyed, conveyedItemInstances);

        // 名称更新
        if (StringUtils.isNotEmpty(exchangeDto.getName())) {
            umlService.updateModel(exchangeDto.getProjectId(), instance.getId(),
                    UMLDefinitionConstants.NamedElement_name, exchangeDto.getName());
        }

        // 更新ExchangeKind属性
        updateExchangeKind(exchangeDto, instance.getUUID());

        String relation = exchangeDto.getRelationId();
        if (StringUtils.isNotEmpty(relation)) {
            affectedRelations.add(relation);
            MetaClassInstance relationship = internalUmlService.fetchInstance(relation, exchangeDto.getProjectId());
            /**
             * 在新建Exchange的情况下，根据情况对两端的属性进行设置
             * 1. connector，如果一端是Property则对type属性进行设置
             * 2. message，如果一端是Property则对type属性进行设置
             */
            MetaClassInstance source = internalUmlService.fetchInstance(exchangeDto.getSource(), exchangeDto.getProjectId());
            MetaClassInstance target = internalUmlService.fetchInstance(exchangeDto.getTarget(), exchangeDto.getProjectId());
            if (exchangeDto instanceof UpdateExchangeDto) {//修改
                MetaClassInstance informationFlow = internalUmlService.fetchInstance(((UpdateExchangeDto) exchangeDto).getExchangeId(), exchangeDto.getProjectId());
                source = internalUmlService.queryInstanceProperty(exchangeDto.getProjectId(), informationFlow, UMLDefinitionConstants.InformationFlow_informationSource);
                target = internalUmlService.queryInstanceProperty(exchangeDto.getProjectId(), informationFlow, UMLDefinitionConstants.InformationFlow_informationTarget);
            } else {//创建
                updateInformationFlowEnds(exchangeDto.getProjectId(), instance, source, target, relationship, exchangeDto.isDirectionSameWithRelation());
            }
            if (internalUmlService.checkInstanceType(exchangeDto.getProjectId(), relationship, UMLDefinitionConstants.Connector)) {
                updateRealizingRelations(exchangeDto.getProjectId(), instance, Collections.singletonList(relationship), UMLDefinitionConstants.InformationFlow_realizingConnector);
            } else if (internalUmlService.checkInstanceType(exchangeDto.getProjectId(), relationship, UMLDefinitionConstants.ActivityEdge)) {
                Set<MetaClassInstance> activityEdges = new HashSet<>();
                activityEdges.add(relationship);
                if (source != null && target != null) {
                    activityEdges.addAll(collectActivityEdgeBySourceTypeAndTargetType(exchangeDto.getProjectId(), source, target, relationship));
                    affectedRelations.addAll(activityEdges.stream().map(BasicRObject::getUUID).collect(Collectors.toList()));
                    createIsCapableToPerformByActivityEdge(exchangeDto, source, target, activityEdges);
                }
                updateRealizingRelations(exchangeDto.getProjectId(), instance, new ArrayList<>(activityEdges), UMLDefinitionConstants.InformationFlow_realizingActivityEdge);
            } else if (internalUmlService.checkInstanceType(exchangeDto.getProjectId(), relationship, UMLDefinitionConstants.Message)) {
                updateRealizingRelations(exchangeDto.getProjectId(), instance, Collections.singletonList(relationship), UMLDefinitionConstants.InformationFlow_realizingMessage);
            } else {
                updateRealizingRelations(exchangeDto.getProjectId(), instance, Collections.singletonList(relationship), UMLDefinitionConstants.InformationFlow_realization);
            }
        }

        return affectedRelations;
    }

    /**
     * 根据起点和终点，及相关的活动边，来创建IsCapabilityToPerform关系
     *
     * @param exchangeDto
     * @param source
     * @param target
     * @param activityEdges
     */
    private void createIsCapableToPerformByActivityEdge(ExchangeDto exchangeDto, MetaClassInstance source, MetaClassInstance target,
                                                  Set<MetaClassInstance> activityEdges) {
        //通过活动边，把模型和行为的IsCapableToPerform关系创建出来
        List<String> propertyKeys = Stream.of(UMLDefinitionConstants.ActivityEdge_source, UMLDefinitionConstants.ActivityEdge_target).collect(Collectors.toList());
        Map<String, Map<String, MofPropertyInfo>> instancePropertyInfoMap = internalUmlService.queryPropertyByModelKeyMap(exchangeDto.getProjectId(), activityEdges.stream().collect(Collectors.toMap(it -> it,
                it -> propertyKeys,
                (s, a) -> a))).getMofPropertyInfoMap();
        Map<String, MofPropertyInfo> instancePropertyInfo;
        List<MetaClassInstance> edgeEnds;
        for (MetaClassInstance activityEdge : activityEdges) {
            instancePropertyInfo = instancePropertyInfoMap.get(activityEdge.getUUID());
            if (instancePropertyInfo != null) {
                edgeEnds = TransformUtil.transformObjectToListInstance(instancePropertyInfo.get(UMLDefinitionConstants.ActivityEdge_source).getValues());
                if (!edgeEnds.isEmpty()) {
                    modelIsCapableToPerformActivity(exchangeDto.getProjectId(), source, edgeEnds.get(0));
                }
                edgeEnds = TransformUtil.transformObjectToListInstance(instancePropertyInfo.get(UMLDefinitionConstants.ActivityEdge_target).getValues());
                if (!edgeEnds.isEmpty()) {
                    modelIsCapableToPerformActivity(exchangeDto.getProjectId(), target, edgeEnds.get(0));
                }
            }
        }
    }

    /**
     * 更新交换的kind
     *
     * @param exchangeDto
     * @param instanceId
     */
    private void updateExchangeKind(ExchangeDto exchangeDto, String instanceId) {
        if (StringUtils.isNotEmpty(exchangeDto.getExchangeKind())) {
            MetaClassInstance exchangeKind = internalUmlService.fetchInstance(exchangeDto.getExchangeKind(), exchangeDto.getProjectId());
            if (exchangeKind != null) {
                if (exchangeDto.getApplyStereotypes().contains(UMLDefinitionConstants.UAF_OperationalExchange)) {
                    umlService.updateModel(exchangeDto.getProjectId(), instanceId, UMLDefinitionConstants.UAF_OperationalExchange_exchangeKind, exchangeKind);
                } else if (exchangeDto.getApplyStereotypes().contains(UMLDefinitionConstants.UAF_ResourceExchange)) {
                    umlService.updateModel(exchangeDto.getProjectId(), instanceId, UMLDefinitionConstants.UAF_ResourceExchange_exchangeKind, exchangeKind);
                } else if (exchangeDto.getApplyStereotypes().contains(UMLDefinitionConstants.UAF_ServiceExchange)) {
                    umlService.updateModel(exchangeDto.getProjectId(), instanceId, UMLDefinitionConstants.UAF_ServiceExchange_exchangeKind, exchangeKind);
                } else {
                    log.info("exchange kind is not updated.");
                }
            }
        }
    }

    /**
     * 根据关系类型更新信息流的实现
     *
     * @param projectId
     * @param exchangeInstance
     * @param relationInstances
     * @param realizingType
     */
    private void updateRealizingRelations(String projectId, MetaClassInstance exchangeInstance, List<MetaClassInstance> relationInstances, String realizingType) {
        if (relationInstances != null && !relationInstances.isEmpty()) {
            List<MetaClassInstance> realizingRelations = new ArrayList<>(internalUmlService.queryListInstanceProperty(projectId, exchangeInstance, realizingType));
            boolean isChange = false;
            for (MetaClassInstance relationInstance : relationInstances) {
                if (!realizingRelations.contains(relationInstance)) {
                    realizingRelations.add(relationInstance);
                    isChange = true;
                }
            }
            if (isChange) {
                umlService.updateModel(projectId, exchangeInstance.getId(), realizingType, realizingRelations);
            }
        }
    }

    /**
     * 模型与活动边上的行为通过IsCapableToPerform关系进行关联
     *
     * @param projectId
     * @param model
     * @param activityNode
     */
    private void modelIsCapableToPerformActivity(String projectId, MetaClassInstance model, MetaClassInstance activityNode) {
        MetaClassInstance behavior = null;
        if (UMLDefinitionConstants.ActivityParameterNode.equals(activityNode.getMetaClass().getId())) {
            behavior = internalUmlService.queryInstanceProperty(projectId, activityNode, UMLDefinitionConstants.ActivityNode_activity);
        } else if (UMLDefinitionConstants.InputPin.equals(activityNode.getMetaClass().getId()) || UMLDefinitionConstants.OutputPin.equals(activityNode.getMetaClass().getId())) {
            MetaClassInstance owner = internalUmlService.queryInstanceProperty(projectId, activityNode, UMLDefinitionConstants.Element_owner);
            if (Objects.nonNull(owner) &&
                    UMLDefinitionConstants.CallBehaviorAction.equals(owner.getMetaClass().getId()) &&
                    !owner.getAppliedStereotypes().isEmpty() &&
                    UAFDefinitionConstants.UAF_CALL_BEHAVIOR_ACTION_STEREOTYPES.contains(owner.getAppliedStereotypes().iterator().next())) {
                behavior = internalUmlService.queryInstanceProperty(projectId, owner, UMLDefinitionConstants.CallBehaviorAction_behavior);
            }
        } else {
            log.info("behavior is null.");
        }

        if(behavior != null) {
            List<MetaClassInstance> relationships = internalUmlService.queryRelationship(
                    projectId,
                    model.getUUID(),
                    Collections.singletonList(behavior.getUUID()));
            if (CollectionUtils.isEmpty(relationships)) {
                CommandParameter parameter = CommandParameter.builder()
                        .type(CommandAddType.RELATIONSHIP)
                        .typeId(UMLDefinitionConstants.Abstraction)
                        .projectId(projectId)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .source(model.getUUID())
                        .target(behavior.getUUID())
                        .parentId(null)
                        .applyStereotypes(Collections.singletonList(UMLDefinitionConstants.UAF_IsCapableToPerform))
                        .build();
                umlService.addModel(parameter);
                umlService.updateModel(projectId, behavior.getUUID(), UMLDefinitionConstants.NamedElement_allocatedFrom, Stream.of(model).collect(Collectors.toList()));
            }
        }
    }

    /**
     * 通过指定活动边，获得关联的调用行为活动/活动参数节点，如果限制了两端类型，则还需要根据两端类型匹配action关联的活动
     *
     * @param projectId
     * @param sourceType
     * @param targetType
     * @param activityEdge
     * @return
     */
    @NotNull
    public Set<MetaClassInstance> collectActivityEdgeBySourceTypeAndTargetType(String projectId, MetaClassInstance sourceType, MetaClassInstance targetType, MetaClassInstance activityEdge) {
        Set<MetaClassInstance> availableEdges = Collections.emptySet();
        MetaClassInstance sourceActivityNode = getSourceActivityNodeFromActivityEdge(projectId, activityEdge);
        MetaClassInstance targetActivityNode = getTargetActivityNodeFromActivityEdge(projectId, activityEdge);
        if (sourceActivityNode != null && targetActivityNode != null) {
            Set<String> sourceActivityNodeTypes = internalUmlService.getGivenTypes(projectId, sourceActivityNode);
            Set<String> targetActivityNodeTypes = internalUmlService.getGivenTypes(projectId, targetActivityNode);
            List<MetaClassInstance> isCapableActivities;
            if (sourceActivityNodeTypes.contains(UMLDefinitionConstants.ControlNode) && (targetActivityNodeTypes.contains(UMLDefinitionConstants.CallBehaviorAction) || targetActivityNodeTypes.contains(UMLDefinitionConstants.ActivityParameterNode))) {
                // 起始端为控制节点，目标端为对象节点
                isCapableActivities = getActivityCanBePerformedByModel(projectId, sourceType);
                availableEdges = getActivityEdgePathByIsCapableActivity(projectId, sourceActivityNode, false, isCapableActivities, new HashSet<>());
                availableEdges.add(activityEdge);
            } else if ((sourceActivityNodeTypes.contains(UMLDefinitionConstants.CallBehaviorAction) || sourceActivityNodeTypes.contains(UMLDefinitionConstants.ActivityParameterNode)) && targetActivityNodeTypes.contains(UMLDefinitionConstants.ControlNode)) {
                // 起始端为对象节点，目标端为控制节点
                isCapableActivities = getActivityCanBePerformedByModel(projectId, targetType);
                availableEdges = getActivityEdgePathByIsCapableActivity(projectId, targetActivityNode, true, isCapableActivities, new HashSet<>());
                availableEdges.add(activityEdge);
            } else if ((sourceActivityNodeTypes.contains(UMLDefinitionConstants.CallBehaviorAction) || sourceActivityNodeTypes.contains(UMLDefinitionConstants.ActivityParameterNode)) &&
                    (targetActivityNodeTypes.contains(UMLDefinitionConstants.CallBehaviorAction) || targetActivityNodeTypes.contains(UMLDefinitionConstants.ActivityParameterNode))) {
                availableEdges = new HashSet<>(1);
                availableEdges.add(activityEdge);
            } else if (sourceActivityNodeTypes.contains(UMLDefinitionConstants.ControlNode) && targetActivityNodeTypes.contains(UMLDefinitionConstants.ControlNode)) {
                isCapableActivities = getActivityCanBePerformedByModel(projectId, sourceType);
                availableEdges = getActivityEdgePathByIsCapableActivity(projectId, sourceActivityNode, false, isCapableActivities, new HashSet<>());
                isCapableActivities = getActivityCanBePerformedByModel(projectId, targetType);
                availableEdges.addAll(getActivityEdgePathByIsCapableActivity(projectId, targetActivityNode, true, isCapableActivities, new HashSet<>()));
                availableEdges.add(activityEdge);
            } else {
                return Collections.emptySet();
            }
        }
        return availableEdges;
    }

    /**
     * 获得活动边的起始活动节点
     *
     * @param projectId
     * @param activityEdge
     * @return
     */
    @Nullable
    public MetaClassInstance getSourceActivityNodeFromActivityEdge(String projectId, MetaClassInstance activityEdge) {
        MetaClassInstance activityNode = internalUmlService.queryInstanceProperty(projectId, activityEdge, UMLDefinitionConstants.ActivityEdge_source);
        //如果是Pin的时候，需要获得Pin的owner
        if (activityNode != null && UMLDefinitionConstants.OutputPin.equals(activityNode.getMetaClass().getId())) {
            return internalUmlService.queryInstanceProperty(projectId, activityNode, UMLDefinitionConstants.Element_owner);
        }
        return activityNode;
    }

    /**
     * 获得活动边的结束活动节点
     *
     * @param projectId
     * @param activityEdge
     * @return
     */
    @Nullable
    public MetaClassInstance getTargetActivityNodeFromActivityEdge(String projectId, MetaClassInstance activityEdge) {
        MetaClassInstance activityNode = internalUmlService.queryInstanceProperty(projectId, activityEdge, UMLDefinitionConstants.ActivityEdge_target);
        //如果是Pin的时候，需要获得Pin的owner
        if (activityNode != null && UMLDefinitionConstants.InputPin.equals(activityNode.getMetaClass().getId())) {
            return internalUmlService.queryInstanceProperty(projectId, activityNode, UMLDefinitionConstants.Element_owner);
        }
        return activityNode;
    }

    /**
     * 根据模型获得可用被执行的活动列表
     *
     * @param projectId
     * @param model
     * @return
     */
    @NotNull
    private List<MetaClassInstance> getActivityCanBePerformedByModel(String projectId, MetaClassInstance model) {
        List<MetaClassInstance> activities = new ArrayList<>();
        if (model != null) {
            internalUmlService.queryListInstanceProperty(projectId, model, UMLDefinitionConstants.NamedElement_clientDependency).stream()
                    .filter(supplier -> supplier.getAppliedStereotypes().contains(UMLDefinitionConstants.UAF_IsCapableToPerform))
                    .forEach(isCapableToPerform -> activities.addAll(internalUmlService.queryListInstanceProperty(projectId, isCapableToPerform, UMLDefinitionConstants.DirectedRelationship_target)));
        }
        return activities;
    }

    /**
     * 根据活动节点获得活动边
     *
     * @param projectId
     * @param startActivityNode
     * @param sourceToTarget
     * @return
     */
    @NotNull
    public List<MetaClassInstance> getActivityEdgesByActivityNode(String projectId, MetaClassInstance startActivityNode, boolean sourceToTarget) {
        if (sourceToTarget) {
            return internalUmlService.queryListInstanceProperty(projectId, startActivityNode, UMLDefinitionConstants.ActivityNode_outgoing);
        } else {
            return internalUmlService.queryListInstanceProperty(projectId, startActivityNode, UMLDefinitionConstants.ActivityNode_incoming);
        }
    }

    /**
     * 根据活动边获得活动节点
     *
     * @param projectId
     * @param edge
     * @param sourceToTarget
     * @return
     */
    @Nullable
    public MetaClassInstance getActivityNodeByActivityEdge(String projectId, MetaClassInstance edge, boolean sourceToTarget) {
        MetaClassInstance activityNode;
        if (sourceToTarget) {
            activityNode = getTargetActivityNodeFromActivityEdge(projectId, edge);
        } else {
            activityNode = getSourceActivityNodeFromActivityEdge(projectId, edge);
        }
        return activityNode;
    }

    /**
     * 根据起始点遍历到第一个UAF的CallBehaviorAction或ActivityParameterNode返回，期间过滤掉控制节点
     *
     * @param projectId
     * @param startActivityNode
     * @param sourceToTarget
     * @param visitedActivityNode
     */
    @NotNull
    private Set<MetaClassInstance> getActivityEdgePathByIsCapableActivity(String projectId, MetaClassInstance startActivityNode, boolean sourceToTarget, List<MetaClassInstance> isCapableActivities, Set<String> visitedActivityNode) {
        Set<MetaClassInstance> availableEdges = new HashSet<>();
        if (visitedActivityNode.contains(startActivityNode.getUUID())) {
            return availableEdges;
        }
        visitedActivityNode.add(startActivityNode.getUUID());
        List<MetaClassInstance> edges = getActivityEdgesByActivityNode(projectId, startActivityNode, sourceToTarget);
        MetaClassInstance activityNode;
        for (MetaClassInstance edge : edges) {
            availableEdges.add(edge);
            activityNode = getActivityNodeByActivityEdge(projectId, edge, sourceToTarget);
            if (internalUmlService.checkInstanceType(projectId, activityNode, UMLDefinitionConstants.ControlNode)) {
                //如果是控制节点，则继续查询下去
                Set<MetaClassInstance> subAvailableEdges = getActivityEdgePathByIsCapableActivity(projectId, activityNode, sourceToTarget, isCapableActivities, visitedActivityNode);
                //如果从底层回来后，没有获得edge，则说明这个分支没有找对应的活动，就删除当前edge
                if (subAvailableEdges.isEmpty()) {
                    availableEdges.remove(edge);
                } else {
                    availableEdges.addAll(subAvailableEdges);
                }
            } else {
                //非控制节点，则需要判断是否为UAF的CallBehaviorAction/ActivityParameterNode
                if(!isActionRelatedToBehavior(projectId, activityNode)) {
                    availableEdges.remove(edge);
                }
            }
        }
        return availableEdges;
    }

    /**
     * 活动节点是否关联行为
     *
     * @param projectId
     * @param activityNode
     * @return
     */
    public boolean isActionRelatedToBehavior(String projectId, MetaClassInstance activityNode) {
        if (UMLDefinitionConstants.CallBehaviorAction.equals(activityNode.getMetaClass().getId())) {
            // 如果能执行的活动非空，则需要限制为指定的活动
            if(!activityNode.getAppliedStereotypes().isEmpty()) {
                MetaClassInstance behavior = internalUmlService.queryInstanceProperty(projectId, activityNode, UMLDefinitionConstants.CallBehaviorAction_behavior);
                return behavior != null;
            }
        } else if (UMLDefinitionConstants.ActivityParameterNode.equals(activityNode.getMetaClass().getId())) {
            MetaClassInstance activity = internalUmlService.queryInstanceProperty(projectId, activityNode, UMLDefinitionConstants.ActivityNode_activity);
            return activity != null;
        } else {
            return false;
        }
        return false;
    }

    /**
     * 更新InformationFlow的一端
     *
     * @param projectId
     * @param informationFlowInstance
     * @param informationFlowSource
     * @param informationFlowTarget
     * @param relation
     */
    private void updateInformationFlowEnds(String projectId, MetaClassInstance informationFlowInstance, MetaClassInstance informationFlowSource,
                                           MetaClassInstance informationFlowTarget, MetaClassInstance relation, boolean directionSameWithRelation) {
        MetaClassInstance newInformationFlowSource = informationFlowSource;
        MetaClassInstance newInformationFlowTarget = informationFlowTarget;
        if (!directionSameWithRelation) {
            newInformationFlowSource = informationFlowTarget;
            newInformationFlowTarget = informationFlowSource;
        }
//        if (UMLDefinitionConstants.Connector.equals(relation.getMetaClass().getId())) {
//            List<MetaClassInstance> connectorEnd = internalUmlService.queryListInstanceProperty(projectId, relation, UMLDefinitionConstants.Connector_end);
//            if (connectorEnd.size() > 1) {
//                MetaClassInstance sourceProperty = directionSameWithRelation ? internalUmlService.queryInstanceProperty(projectId, connectorEnd.get(0),
//                        UMLDefinitionConstants.ConnectorEnd_role) : internalUmlService.queryInstanceProperty(projectId, connectorEnd.get(1),
//                        UMLDefinitionConstants.ConnectorEnd_role);
//                MetaClassInstance targetProperty = directionSameWithRelation ? internalUmlService.queryInstanceProperty(projectId, connectorEnd.get(1),
//                        UMLDefinitionConstants.ConnectorEnd_role) : internalUmlService.queryInstanceProperty(projectId, connectorEnd.get(0),
//                        UMLDefinitionConstants.ConnectorEnd_role);
//                updatePropertyType(projectId, sourceProperty, newInformationFlowSource);
//                updatePropertyType(projectId, targetProperty, newInformationFlowTarget);
//            }
//        } else
        if (UMLDefinitionConstants.Message.equals(relation.getMetaClass().getId())) {
            MetaClassInstance sendEvent = internalUmlService.queryInstanceProperty(projectId, relation, UMLDefinitionConstants.Message_sendEvent);
            updateMessageEnd(projectId, sendEvent, informationFlowSource);
            MetaClassInstance receiveEvent = internalUmlService.queryInstanceProperty(projectId, relation, UMLDefinitionConstants.Message_receiveEvent);
            updateMessageEnd(projectId, receiveEvent, informationFlowTarget);
        } else {
            log.info("the type of the ends is not connector nor message.");
        }
        umlService.updateModel(projectId, informationFlowInstance.getId(), UMLDefinitionConstants.InformationFlow_informationSource, Collections.singletonList(newInformationFlowSource));
        umlService.updateModel(projectId, informationFlowInstance.getId(), UMLDefinitionConstants.InformationFlow_informationTarget, Collections.singletonList(newInformationFlowTarget));
    }

    /**
     * 设置
     *
     * @param projectId
     * @param property
     * @param newInformationFlow
     */
    private void updatePropertyType(String projectId, MetaClassInstance property, MetaClassInstance newInformationFlow) {
        if (property != null) {
            MetaClassInstance propertyType = internalUmlService.queryInstanceProperty(projectId, property, UMLDefinitionConstants.TypedElement_type);
            if (propertyType == null) {
                umlService.updateModel(projectId, property.getId(), UMLDefinitionConstants.TypedElement_type, newInformationFlow);
            }
        }
    }

    /**
     * 更新message两端的类型到lifeline的represents里面
     *
     * @param projectId
     * @param eventEnd
     * @param informationFlowEnd
     */
    private void updateMessageEnd(String projectId, MetaClassInstance eventEnd, MetaClassInstance informationFlowEnd) {
        if (UMLDefinitionConstants.MessageOccurrenceSpecification.equals(eventEnd.getMetaClass().getId())) {
            List<MetaClassInstance> covered = internalUmlService.queryListInstanceProperty(projectId, eventEnd, UMLDefinitionConstants.OccurrenceSpecification_covered);
            if (!covered.isEmpty()) {
                MetaClassInstance represents = internalUmlService.queryInstanceProperty(projectId, covered.get(0), UMLDefinitionConstants.Lifeline_represents);
                if (represents == null) {
                    umlService.updateModel(projectId, covered.get(0).getId(), UMLDefinitionConstants.Lifeline_represents, Collections.singletonList(informationFlowEnd));
                } else if (UMLDefinitionConstants.Property.equals(represents.getMetaClass().getId())) {
                    MetaClassInstance propertyType = internalUmlService.queryInstanceProperty(projectId, represents, UMLDefinitionConstants.TypedElement_type);
                    if (propertyType == null) {
                        umlService.updateModel(projectId, represents.getId(), UMLDefinitionConstants.TypedElement_type, informationFlowEnd);
                    }
                } else {
                    log.info("message end is not updated.");
                }
            }
        }
    }

    /**
     * 更新交换
     *
     * @param updateExchangeDto
     * @return
     */
    @NotNull
    public ModelResultVo updateExchange(UpdateExchangeDto updateExchangeDto) {
        final ModelResultVo modelResultVo = new ModelResultVo();

        MetaClassInstance instance = internalUmlService.fetchInstance(updateExchangeDto.getExchangeId(),
                updateExchangeDto.getProjectId());
        if (Objects.isNull(instance)) {
            return modelResultVo;
        }

        final String projectId = updateExchangeDto.getProjectId();
        final Project project = projectManager.getProject(projectId);
        if (Objects.isNull(project)) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_NOT_FOUND);
        }
        LocalTransaction transaction = transactionService.createTransaction(projectId, UPDATE_PROPERTY);
        try {
            updateExchangeRelated(projectId, updateExchangeDto, instance, transaction, modelResultVo);
        } catch (AbortExecutionException e) {
            transactionService.rollBack(projectId, transaction);
            throw e;
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROPERTY_UPDATE_ERROR, e);
        }

        return modelResultVo;
    }

    /**
     * 更新转换相关的属性信息
     *
     * @param projectId
     * @param exchangeDto
     * @param exchangeInstance
     * @param transaction
     * @param modelResultVo
     * @throws TransactionNotExistingException
     * @throws LocalTransactionNotStartException
     */
    private void updateExchangeRelated(String projectId, ExchangeDto exchangeDto, MetaClassInstance exchangeInstance,
                                       LocalTransaction transaction, ModelResultVo modelResultVo)
            throws TransactionNotExistingException, LocalTransactionNotStartException {
        Set<String> affectedRelations = updateExchangeProperties(exchangeDto, exchangeInstance);
        transactionService.commit(projectId);
        InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        if (!affectedRelations.isEmpty()) {
            for (String relation : affectedRelations) {
                if (!modelResultVo.getModifyModel().contains(relation)) {
                    modelResultVo.getModifyModel().add(relation);
                }
            }
        }
    }

    /**
     * 通过转换类型和传输模型获得exchangeKind
     *
     * @param projectId
     * param exchangeStereotype
     * @param conveyedId
     * @return
     */
    @NotNull
    public String queryExchangeKindByConveyed(String projectId, String exchangeStereotype, String conveyedId) {
        MetaClassInstance conveyed = internalUmlService.fetchInstance(conveyedId, projectId);
        if (conveyed != null) {
            Set<String> types = internalUmlService.getGivenTypes(projectId, conveyed);
            return ExchangeUtils.getExchangeKindByConveyedType(exchangeStereotype, types);
        }
        return Strings.EMPTY;
    }

    /**
     * 指定的模型是否可以被传输
     *
     * @param projectId
     * @param exchangeStereotype
     * @param conveyedId
     * @return
     */
    @NotNull
    public Boolean canConveyed(String projectId, String exchangeStereotype, String conveyedId) {
        MetaClassInstance conveyed = internalUmlService.fetchInstance(conveyedId, projectId);
        if (conveyed != null) {
            Set<String> types = internalUmlService.getGivenTypes(projectId, conveyed);
            if ((UMLDefinitionConstants.UAF_OperationalExchange.equals(exchangeStereotype) && types.contains(UMLDefinitionConstants.UAF_OperationalExchangeItem)) ||
                    (UMLDefinitionConstants.UAF_ResourceExchange.equals(exchangeStereotype) && types.contains(UMLDefinitionConstants.UAF_ResourceExchangeItem)) ||
                    (UMLDefinitionConstants.UAF_ServiceExchange.equals(exchangeStereotype) && types.contains(UMLDefinitionConstants.UAF_ServiceExchangeItem)) ||
                    (UMLDefinitionConstants.UAF_StrategicExchange.equals(exchangeStereotype) && types.contains(UMLDefinitionConstants.UAF_StrategicExchangeItem))) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }
}

